<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';

import {
  AimOutlined,
  BookOutlined,
  CloudOutlined,
  CrownOutlined,
  FireOutlined,
  HistoryOutlined,
  PictureOutlined,
  SafetyCertificateOutlined,
  SkinOutlined,
  SyncOutlined,
  TeamOutlined,
  TrophyOutlined,
} from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import dayjs from 'dayjs';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

import { offerings } from '../../data/shrineData';
import { audioManager } from '../../utils/audioManager';
import InteriorShrine from './InteriorShrine.vue';

const containerRef = ref<HTMLElement>();
const autoRotate = ref(false); // 默认不自动旋转
const currentTheme = ref<'ming' | 'qing' | 'song'>('ming');
const nftModalVisible = ref(false);
const worshipModalVisible = ref(false);
const recordModalVisible = ref(false);
const tabletModalVisible = ref(false); // 牌位详情Modal
const doorOpen = ref(false); // 门是否打开
const worshipStep = ref(0);
const selectedAncestor = ref('');
const selectedOfferings = ref<string[]>([]);
const selectedTablet = ref<any>(null); // 选中的牌位
const submitting = ref(false);
const weatherEffect = ref<'rain' | 'snow' | 'sunny'>('sunny');
const timeOfDay = ref<'day' | 'night'>('day');
const festival = ref<string>(''); // 当前节日
const showFestivalDecoration = ref(false); // 是否显示节日装饰
const onlineUsers = ref(3); // 在线人数
const showInterior = ref(false); // 是否显示室内组件

const worshipData = ref({
  title: '',
  content: '',
  onChain: true,
});

// 牌位信息列表
const tablets = ref([
  {
    id: 'tablet-1',
    name: '朱元璋',
    title: '太祖洪武皇帝',
    birthYear: 1328,
    deathYear: 1398,
    position: '正中央主位',
    achievement: '建立大明王朝，驱逐蒙元，统一中原',
    biography:
      '明太祖朱元璋（1328年10月21日-1398年6月24日），濠州钟离人，汉族。原名重八，后取名兴宗，参加郭子兴领导的红巾军后改名为元璋。明朝开国皇帝，政治家，军事统帅。25年戎马生涯，统一全国，建立大明王朝。在位期间，政治上废除丞相，设立六部，加强中央集权；经济上推行屯田政策，兴修水利；文化上编修《大明律》，设立科举制度。开创洪武之治，为明朝268年基业奠定了坚实基础。',
    worshipCount: 1586,
    recentWorship: [
      {
        id: 1,
        date: '2025-10-01',
        worshiper: '朱允炆',
        offerings: '香烛、鲜花、水果',
      },
      { id: 2, date: '2025-09-15', worshiper: '朱棣', offerings: '三牲、美酒' },
      {
        id: 3,
        date: '2025-08-20',
        worshiper: '朱高炽',
        offerings: '香烛、祭文',
      },
    ],
  },
  {
    id: 'tablet-2',
    name: '朱棣',
    title: '成祖永乐皇帝',
    birthYear: 1360,
    deathYear: 1424,
    position: '左侧第一位',
    achievement: '迁都北京，五征漠北，永乐盛世',
    biography:
      '明成祖朱棣（1360年5月2日-1424年8月12日），明太祖朱元璋第四子，母孝慈高皇后马氏。洪武三年，受封燕王，镇守北平。建文元年，发动靖难之役，攻占南京，夺取帝位。永乐年间，迁都北京，编修《永乐大典》，五次亲征漠北，三次派郑和下西洋，开拓海上丝绸之路，使明朝国力达到顶峰。在位22年，政绩卓著，开创永乐盛世。',
    worshipCount: 1248,
    recentWorship: [
      {
        id: 1,
        date: '2025-09-28',
        worshiper: '朱高炽',
        offerings: '香烛、祭文',
      },
      {
        id: 2,
        date: '2025-09-01',
        worshiper: '朱瞻基',
        offerings: '鲜花、水果',
      },
    ],
  },
  {
    id: 'tablet-3',
    name: '朱高炽',
    title: '仁宗洪熙皇帝',
    birthYear: 1378,
    deathYear: 1425,
    position: '左侧第二位',
    achievement: '仁政爱民，与民休息，洪熙之治',
    biography:
      '明仁宗朱高炽（1378年8月16日-1425年5月29日），明成祖朱棣长子，母仁孝文皇后徐氏。性格仁厚，深得祖父朱元璋喜爱。永乐二十二年即位，改元洪熙。在位期间，停止下西洋，罢除采办珠宝，减免赋税，平反冤狱，重用贤才，实行仁政，使百姓得以休养生息。虽在位仅10个月，但政绩斐然，史称"洪熙之治"。',
    worshipCount: 892,
    recentWorship: [
      {
        id: 1,
        date: '2025-09-20',
        worshiper: '朱瞻基',
        offerings: '香烛、鲜花',
      },
    ],
  },
  {
    id: 'tablet-4',
    name: '朱瞻基',
    title: '宣宗宣德皇帝',
    birthYear: 1398,
    deathYear: 1435,
    position: '右侧第一位',
    achievement: '宣德盛世，文治武功，促织图治',
    biography:
      '明宣宗朱瞻基（1398年3月16日-1435年1月31日），明仁宗朱高炽长子，母诚孝昭皇后张氏。洪熙元年即位，改元宣德。在位期间，内阁制度逐渐完善，政治清明，经济繁荣，社会稳定，国力强盛。他本人精通书画，喜好促织（蟋蟀），雅好翰墨，是一位多才多艺的皇帝。与其父仁宗并称"仁宣之治"，是明朝国力最强盛的时期之一。',
    worshipCount: 756,
    recentWorship: [
      {
        id: 1,
        date: '2025-09-15',
        worshiper: '朱祁镇',
        offerings: '香烛、水果',
      },
    ],
  },
  {
    id: 'tablet-5',
    name: '马皇后',
    title: '孝慈高皇后',
    birthYear: 1332,
    deathYear: 1382,
    position: '右侧第二位',
    achievement: '贤德皇后，辅佐太祖，母仪天下',
    biography:
      '孝慈高皇后马氏（1332年-1382年），安徽宿州人，明太祖朱元璋的原配妻子。自幼聪颖贤淑，嫁朱元璋后，与其患难与共，辅佐朱元璋成就帝业。建国后母仪天下，勤俭持家，关心百姓疾苦，多次劝谏朱元璋宽厚待人，减轻刑罚，保全了许多大臣的性命。她深明大义，不干预朝政，却在关键时刻能提出正确建议。洪武十五年病逝，朱元璋悲痛欲绝，此后再未立皇后。',
    worshipCount: 1342,
    recentWorship: [
      {
        id: 1,
        date: '2025-10-08',
        worshiper: '朱标妃',
        offerings: '鲜花、香烛、祭文',
      },
      {
        id: 2,
        date: '2025-09-25',
        worshiper: '朱允炆',
        offerings: '鲜花、水果',
      },
    ],
  },
]);

// 祖先列表
const ancestors = ref([
  {
    id: 'zhu-1-1',
    name: '朱元璋',
    title: '太祖洪武皇帝',
    avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuYuanzhang',
  },
  {
    id: 'zhu-2-4',
    name: '朱棣',
    title: '成祖永乐皇帝',
    avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuDi',
  },
  {
    id: 'zhu-3-1',
    name: '朱高炽',
    title: '仁宗洪熙皇帝',
    avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuGaochi',
  },
  {
    id: 'zhu-4-1',
    name: '朱瞻基',
    title: '宣宗宣德皇帝',
    avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuZhanji',
  },
]);

// 祭品列表（从 shrineData.ts 导入，包含20个祭品：6个传统 + 10个奢侈品 + 4个现代生活品）
// offerings 已在顶部导入

// 祭祀记录
const worshipRecords = ref([
  {
    id: 1,
    ancestorName: '朱元璋',
    ancestorAvatar:
      'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuYuanzhang',
    title: '清明祭祖',
    offerings: ['上香', '献花', '果品'],
    content: '太祖功德，永垂不朽。清明时节，特来祭拜...',
    time: '2025-04-04T10:00:00Z',
    sbtMinted: true,
    sbtTokenId: 'SBT-4001',
  },
  {
    id: 2,
    ancestorName: '朱棣',
    ancestorAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ZhuDi',
    title: '重阳追思',
    offerings: ['上香', '美酒'],
    content: '成祖武功，开创永乐盛世。重阳佳节，缅怀先祖...',
    time: '2024-10-09T10:00:00Z',
    sbtMinted: true,
    sbtTokenId: 'SBT-4002',
  },
]);

let scene: THREE.Scene;
let camera: THREE.PerspectiveCamera;
let renderer: THREE.WebGLRenderer;
let controls: OrbitControls;
let shrine: THREE.Group;
let animationId: number;
let raycaster: THREE.Raycaster;
let mouse: THREE.Vector2;
const clickableObjects: THREE.Mesh[] = [];
const smokeParticles: THREE.Points[] = [];
let rainParticles: null | THREE.Points = null;
let snowParticles: null | THREE.Points = null;
let directionalLight: THREE.DirectionalLight;
let shrineWalls: null | THREE.Mesh = null; // 祠堂墙体引用
let shrineDoor: null | THREE.Mesh = null; // 祠堂门引用，用于开门动画
let incenseBurner: null | THREE.Group = null; // 香炉引用，用于开门时隐藏
let shrinePillars: THREE.Mesh[] = []; // 柱子引用数组，用于开门时变透明
let shrineRoof: null | THREE.Group = null; // 屋顶引用，用于开门时隐藏

// NFT列表
const nftList = ref([
  {
    id: 1,
    name: '皇族身份SBT',
    description: '朱氏皇族成员证明',
    tokenId: 'SBT-1013',
    icon: CrownOutlined,
    color: '#faad14',
  },
  {
    id: 2,
    name: '名人SBT',
    description: '书画名家荣誉',
    tokenId: 'SBT-2004',
    icon: TrophyOutlined,
    color: '#1890ff',
  },
  {
    id: 3,
    name: '祭礼SBT',
    description: '参与祭祖仪式',
    tokenId: 'SBT-4001',
    icon: FireOutlined,
    color: '#ff4d4f',
  },
  {
    id: 4,
    name: '学者SBT',
    description: '完成课程学习',
    tokenId: 'SBT-3001',
    icon: BookOutlined,
    color: '#52c41a',
  },
]);

onMounted(() => {
  if (containerRef.value) {
    initScene();
    createShrine();
    createLights();
    createGround();
    initRaycaster();
    checkFestival();
    audioManager.init(); // 初始化音频系统
    audioManager.playBGM('guzheng-bg'); // 播放古筝背景音乐
    animate();

    window.addEventListener('resize', handleResize);
    window.addEventListener('click', handleClick);
  }
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize);
  window.removeEventListener('click', handleClick);
  audioManager.stopBGM();
  audioManager.stopAllAmbient();
  if (animationId) {
    cancelAnimationFrame(animationId);
  }
  renderer?.dispose();
});

/**
 * 初始化3D场景
 */
function initScene() {
  // 场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x87_ce_eb); // 天空蓝
  scene.fog = new THREE.Fog(0x87_ce_eb, 50, 200);

  // 相机
  const width = containerRef.value!.clientWidth;
  const height = containerRef.value!.clientHeight;
  camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 1000); // 稍微减小视角
  camera.position.set(0, 30, 50);
  camera.lookAt(0, 0, 0);

  // 渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(width, height);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  containerRef.value!.append(renderer.domElement);

  // 控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.minDistance = 20;
  controls.maxDistance = 100;
  controls.maxPolarAngle = Math.PI / 2.1;
  controls.autoRotate = false; // 默认不自动旋转
  controls.autoRotateSpeed = 1;
}

/**
 * 创建祠堂建筑
 */
function createShrine() {
  shrine = new THREE.Group();

  // 主殿 - 大雄宝殿风格
  const mainHallMaterial = getMingThemeMaterial();

  // 主殿基座
  const baseGeometry = new THREE.BoxGeometry(20, 1, 15);
  const baseMaterial = new THREE.MeshStandardMaterial({ color: 0x8b_73_55 });
  const base = new THREE.Mesh(baseGeometry, baseMaterial);
  base.position.y = 0.5;
  base.castShadow = true;
  base.receiveShadow = true;
  shrine.add(base);

  // 主殿墙体 - 使用透明材质，方便开门时看到内部
  const wallGeometry = new THREE.BoxGeometry(18, 12, 12);
  const wallMaterial = new THREE.MeshStandardMaterial({
    color: 0xff_6b_6b,
    transparent: true,
    opacity: 1,
    side: THREE.DoubleSide,
  });
  shrineWalls = new THREE.Mesh(wallGeometry, wallMaterial);
  shrineWalls.position.y = 7;
  shrineWalls.castShadow = true;
  shrineWalls.receiveShadow = true;
  shrine.add(shrineWalls);

  // 屋顶 - 重檐歇山顶
  shrineRoof = createRoof(shrine, 0, 13, 0);

  // 柱子
  shrinePillars = createPillars(shrine);

  // 创建优化的大门
  shrineDoor = createOptimizedDoor(shrine);

  // 门匾
  const plaqueGeometry = new THREE.BoxGeometry(8, 2, 0.3);
  const plaqueMaterial = new THREE.MeshStandardMaterial({ color: 0xff_d7_00 });
  const plaque = new THREE.Mesh(plaqueGeometry, plaqueMaterial);
  plaque.position.set(0, 11, 6.5);
  shrine.add(plaque);

  // 香炉（前方）
  incenseBurner = createIncenseBurner(shrine, 0, 1, 15);

  // 牌位架（内部模拟）
  createTabletStand(shrine, 0, 5, -3);

  scene.add(shrine);
}

/**
 * 创建屋顶
 */
function createRoof(
  parent: THREE.Group,
  x: number,
  y: number,
  z: number,
): THREE.Group {
  const roofGroup = new THREE.Group();

  // 第一层屋顶（大）
  const roofGeometry1 = new THREE.ConeGeometry(14, 3, 4);
  const roofMaterial = new THREE.MeshStandardMaterial({
    color: 0xff_a5_00, // 橙黄色琉璃瓦
    metalness: 0.5,
    roughness: 0.3,
  });
  const roof1 = new THREE.Mesh(roofGeometry1, roofMaterial);
  roof1.position.set(0, 0, 0);
  roof1.rotation.y = Math.PI / 4;
  roof1.castShadow = true;
  roofGroup.add(roof1);

  // 第二层屋顶（小）
  const roofGeometry2 = new THREE.ConeGeometry(12, 2, 4);
  const roof2 = new THREE.Mesh(roofGeometry2, roofMaterial);
  roof2.position.set(0, 2.5, 0);
  roof2.rotation.y = Math.PI / 4;
  roof2.castShadow = true;
  roofGroup.add(roof2);

  // 顶部装饰
  const topGeometry = new THREE.SphereGeometry(0.8, 16, 16);
  const topMaterial = new THREE.MeshStandardMaterial({
    color: 0xff_d7_00,
    metalness: 0.8,
  });
  const top = new THREE.Mesh(topGeometry, topMaterial);
  top.position.set(0, 4, 0);
  roofGroup.add(top);

  roofGroup.position.set(x, y, z);
  parent.add(roofGroup);

  return roofGroup;
}

/**
 * 创建优化的室内墙壁
 */
function createInteriorWalls(parent: THREE.Group) {
  // 后墙（牌位背景墙）
  const backWallGeometry = new THREE.BoxGeometry(20, 12, 0.5);
  const backWallMaterial = new THREE.MeshStandardMaterial({
    color: 0x2c_18_10, // 深棕色，庄重
    metalness: 0.2,
    roughness: 0.8,
  });
  shrineWalls = new THREE.Mesh(backWallGeometry, backWallMaterial);
  shrineWalls.position.set(0, 6, -6); // 后墙位置
  shrineWalls.castShadow = true;
  shrineWalls.receiveShadow = true;
  parent.add(shrineWalls);

  // 侧墙（简化，只显示部分）
  const sideWallGeometry = new THREE.BoxGeometry(0.5, 12, 10);
  const sideWallMaterial = new THREE.MeshStandardMaterial({
    color: 0x3c_28_20, // 稍浅的棕色
    metalness: 0.2,
    roughness: 0.8,
  });

  // 左墙
  const leftWall = new THREE.Mesh(sideWallGeometry, sideWallMaterial);
  leftWall.position.set(-10, 6, 0);
  leftWall.castShadow = true;
  leftWall.receiveShadow = true;
  parent.add(leftWall);

  // 右墙
  const rightWall = new THREE.Mesh(sideWallGeometry, sideWallMaterial);
  rightWall.position.set(10, 6, 0);
  rightWall.castShadow = true;
  rightWall.receiveShadow = true;
  parent.add(rightWall);

  // 地面
  const floorGeometry = new THREE.BoxGeometry(20, 0.2, 12);
  const floorMaterial = new THREE.MeshStandardMaterial({
    color: 0x4a_3c_2a, // 木地板色
    metalness: 0.1,
    roughness: 0.9,
  });
  const floor = new THREE.Mesh(floorGeometry, floorMaterial);
  floor.position.set(0, 0, 0);
  floor.receiveShadow = true;
  parent.add(floor);
}

/**
 * 创建优化的大门
 */
function createOptimizedDoor(parent: THREE.Group): THREE.Mesh {
  const doorGroup = new THREE.Group();

  // 门框
  const frameGeometry = new THREE.BoxGeometry(8, 12, 0.8);
  const frameMaterial = new THREE.MeshStandardMaterial({
    color: 0x2c_18_10, // 深棕色门框
    metalness: 0.3,
  });
  const doorFrame = new THREE.Mesh(frameGeometry, frameMaterial);
  doorFrame.position.set(0, 6, 6.5);
  doorGroup.add(doorFrame);

  // 双开门
  const doorGeometry = new THREE.BoxGeometry(3, 10, 0.3);
  const doorMaterial = new THREE.MeshStandardMaterial({
    color: 0x4a_3c_2a, // 木门色
    metalness: 0.2,
    roughness: 0.8,
  });

  // 左门
  const leftDoor = new THREE.Mesh(doorGeometry, doorMaterial);
  leftDoor.position.set(-1.5, 6, 6.8);
  leftDoor.userData = { clickable: true, type: 'door', side: 'left' };
  clickableObjects.push(leftDoor);
  doorGroup.add(leftDoor);

  // 右门
  const rightDoor = new THREE.Mesh(doorGeometry, doorMaterial);
  rightDoor.position.set(1.5, 6, 6.8);
  rightDoor.userData = { clickable: true, type: 'door', side: 'right' };
  clickableObjects.push(rightDoor);
  doorGroup.add(rightDoor);

  // 门把手
  const handleGeometry = new THREE.SphereGeometry(0.1, 8, 8);
  const handleMaterial = new THREE.MeshStandardMaterial({
    color: 0xff_d7_00, // 金色把手
    metalness: 0.8,
  });

  const leftHandle = new THREE.Mesh(handleGeometry, handleMaterial);
  leftHandle.position.set(-0.8, 6, 6.9);
  doorGroup.add(leftHandle);

  const rightHandle = new THREE.Mesh(handleGeometry, handleMaterial);
  rightHandle.position.set(0.8, 6, 6.9);
  doorGroup.add(rightHandle);

  parent.add(doorGroup);

  // 保存门的引用（使用左门作为主引用）
  leftDoor.userData.rightDoor = rightDoor;
  return leftDoor;
}

/**
 * 创建柱子
 */
function createPillars(parent: THREE.Group): THREE.Mesh[] {
  const pillarGeometry = new THREE.CylinderGeometry(0.4, 0.5, 12, 12);
  const pillarMaterial = new THREE.MeshStandardMaterial({ color: 0x8b_00_00 });

  const positions = [
    [-7, 7, 5],
    [7, 7, 5],
    [-7, 7, -5],
    [7, 7, -5],
  ];

  const pillars: THREE.Mesh[] = [];
  positions.forEach(([x, y, z]) => {
    const pillar = new THREE.Mesh(pillarGeometry, pillarMaterial);
    pillar.position.set(x, y, z);
    pillar.castShadow = true;
    parent.add(pillar);
    pillars.push(pillar);
  });

  return pillars;
}

/**
 * 创建香炉
 */
function createIncenseBurner(
  parent: THREE.Group,
  x: number,
  y: number,
  z: number,
): THREE.Group {
  const burnerGroup = new THREE.Group();
  burnerGroup.name = 'incense-burner';

  // 香炉底座
  const baseGeometry = new THREE.CylinderGeometry(1.5, 2, 1, 16);
  const baseMaterial = new THREE.MeshStandardMaterial({
    color: 0x8b_73_55,
    metalness: 0.6,
  });
  const base = new THREE.Mesh(baseGeometry, baseMaterial);
  base.position.y = 0.5;
  base.userData = { clickable: true, type: 'incense-burner' };
  clickableObjects.push(base);
  burnerGroup.add(base);

  // 香炉主体
  const bodyGeometry = new THREE.CylinderGeometry(1.2, 1.5, 1.5, 16);
  const bodyMaterial = new THREE.MeshStandardMaterial({
    color: 0xcd_7f_32,
    metalness: 0.7,
  });
  const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
  body.position.y = 1.75;
  body.userData = { clickable: true, type: 'incense-burner' };
  clickableObjects.push(body);
  burnerGroup.add(body);

  // 香（3根）
  for (let i = 0; i < 3; i++) {
    const incenseGeometry = new THREE.CylinderGeometry(0.05, 0.05, 2, 8);
    const incenseMaterial = new THREE.MeshStandardMaterial({
      color: 0x8b_45_13,
    });
    const incense = new THREE.Mesh(incenseGeometry, incenseMaterial);
    incense.position.set((i - 1) * 0.3, 3.5, 0);
    burnerGroup.add(incense);

    // 改进的烟雾粒子效果
    createSmokeParticles(burnerGroup, (i - 1) * 0.3, 4.5, 0);
  }

  burnerGroup.position.set(x, y, z);
  parent.add(burnerGroup);

  return burnerGroup;
}

/**
 * 创建烟雾粒子系统
 */
function createSmokeParticles(
  parent: THREE.Group,
  x: number,
  y: number,
  z: number,
) {
  const particleCount = 50;
  const particles = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const velocities: number[] = [];

  for (let i = 0; i < particleCount; i++) {
    positions[i * 3] = x + (Math.random() - 0.5) * 0.2;
    positions[i * 3 + 1] = y + Math.random() * 2;
    positions[i * 3 + 2] = z + (Math.random() - 0.5) * 0.2;

    velocities.push(
      (Math.random() - 0.5) * 0.02,
      Math.random() * 0.05 + 0.02,
      (Math.random() - 0.5) * 0.02,
    );
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));

  const particleMaterial = new THREE.PointsMaterial({
    color: 0xcc_cc_cc,
    size: 0.15,
    transparent: true,
    opacity: 0.4,
    blending: THREE.AdditiveBlending,
  });

  const particleSystem = new THREE.Points(particles, particleMaterial);
  particleSystem.userData = { velocities, baseY: y };
  smokeParticles.push(particleSystem);
  parent.add(particleSystem);
}

/**
 * 创建竖向文字精灵（用于牌位标签）- 逐字竖排
 */
function createTextSprite(text: string): THREE.Sprite {
  // 创建 canvas（竖向布局）
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d')!;

  const fontSize = 36;
  const padding = 10;
  const charSpacing = 8; // 字间距

  // 计算canvas尺寸
  canvas.width = fontSize + padding * 2;
  canvas.height = text.length * (fontSize + charSpacing) + padding * 2;

  // 绘制背景（深红色，更庄重）
  context.fillStyle = 'rgba(139, 0, 0, 0.85)';
  context.fillRect(0, 0, canvas.width, canvas.height);

  // 绘制边框（金色）
  context.strokeStyle = '#FFD700';
  context.lineWidth = 3;
  context.strokeRect(2, 2, canvas.width - 4, canvas.height - 4);

  // 设置字体
  context.font = `bold ${fontSize}px "STKaiti", "KaiTi", "Microsoft YaHei", SimHei, serif`;
  context.fillStyle = '#FFD700';
  context.textAlign = 'center';
  context.textBaseline = 'top';
  context.shadowColor = 'rgba(255, 215, 0, 0.6)';
  context.shadowBlur = 6;

  // 逐字竖排绘制文字（从上到下）
  const chars = Array.from(text); // 将字符串转换为字符数组
  for (const [i, char] of chars.entries()) {
    const x = canvas.width / 2;
    const y = padding + i * (fontSize + charSpacing);
    context.fillText(char, x, y);
  }

  // 创建纹理
  const texture = new THREE.CanvasTexture(canvas);
  texture.needsUpdate = true;

  // 创建精灵材质
  const spriteMaterial = new THREE.SpriteMaterial({
    map: texture,
    transparent: true,
    opacity: 1,
    depthTest: true, // 正常深度测试，让它看起来更自然
  });

  // 创建精灵
  const sprite = new THREE.Sprite(spriteMaterial);
  // 根据文字长度调整高度
  const aspectRatio = canvas.width / canvas.height;
  const spriteHeight = 3.5; // 固定高度
  sprite.scale.set(spriteHeight * aspectRatio, spriteHeight, 1);
  sprite.renderOrder = 100; // 确保在牌位之上

  return sprite;
}

/**
 * 创建牌位架
 */
function createTabletStand(
  parent: THREE.Group,
  x: number,
  y: number,
  z: number,
) {
  const standGroup = new THREE.Group();

  // 架子
  // 移除架子，直接放置牌位
  // const shelfGeometry = new THREE.BoxGeometry(12, 0.5, 2);
  // const shelfMaterial = new THREE.MeshStandardMaterial({ color: 0x8b_45_13 });
  // const shelf = new THREE.Mesh(shelfGeometry, shelfMaterial);
  // standGroup.add(shelf);

  // 牌位（5个）- 优化显示效果
  tablets.value.forEach((tabletData, i) => {
    // 增大牌位尺寸，更适合室内全景
    const tabletGeometry = new THREE.BoxGeometry(2.5, 5, 0.3);
    const tabletMaterial = new THREE.MeshStandardMaterial({
      color: 0xff_d7_00,
      emissive: 0xff_d7_00,
      emissiveIntensity: 0.4,
      metalness: 0.7,
      roughness: 0.3,
    });
    const tablet = new THREE.Mesh(tabletGeometry, tabletMaterial);
    tablet.position.set((i - 2) * 3.5, 3, 0); // 稍微高一些，间距大一些
    tablet.castShadow = true;
    tablet.userData = {
      clickable: true,
      type: 'tablet',
      tabletId: tabletData.id,
      tabletIndex: i,
    };
    clickableObjects.push(tablet);
    standGroup.add(tablet);

    // 为每个牌位添加更强的点光源
    const tabletLight = new THREE.PointLight(0xff_d7_00, 0.8, 8);
    tabletLight.position.set((i - 2) * 3.5, 3, 1);
    standGroup.add(tabletLight);

    // 添加文字标签（称号）在牌位表面
    const textSprite = createTextSprite(tabletData.title);
    textSprite.position.set((i - 2) * 3.5, 5.5, 0.2); // 在牌位上方
    standGroup.add(textSprite);

    // 添加牌位底座
    const baseGeometry = new THREE.BoxGeometry(3, 0.3, 1);
    const baseMaterial = new THREE.MeshStandardMaterial({
      color: 0x8b_45_13, // 棕色底座
      metalness: 0.3,
      roughness: 0.7,
    });
    const base = new THREE.Mesh(baseGeometry, baseMaterial);
    base.position.set((i - 2) * 3.5, 0.5, 0);
    base.receiveShadow = true;
    standGroup.add(base);
  });

  standGroup.position.set(x, y, z);
  parent.add(standGroup);
}

/**
 * 获取明朝主题材质
 */
function getMingThemeMaterial() {
  return new THREE.MeshStandardMaterial({
    color: 0xff_6b_6b, // 明朝红
    metalness: 0.2,
    roughness: 0.7,
  });
}

/**
 * 创建光照
 */
function createLights() {
  // 环境光
  const ambientLight = new THREE.AmbientLight(0xff_ff_ff, 0.5);
  scene.add(ambientLight);

  // 主光源（太阳）
  directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 1);
  directionalLight.position.set(30, 50, 30);
  directionalLight.castShadow = true;
  directionalLight.shadow.camera.left = -50;
  directionalLight.shadow.camera.right = 50;
  directionalLight.shadow.camera.top = 50;
  directionalLight.shadow.camera.bottom = -50;
  directionalLight.shadow.mapSize.width = 2048;
  directionalLight.shadow.mapSize.height = 2048;
  scene.add(directionalLight);

  // 补光
  const fillLight = new THREE.DirectionalLight(0xff_ff_ff, 0.3);
  fillLight.position.set(-30, 30, -30);
  scene.add(fillLight);
}

/**
 * 创建地面
 */
function createGround() {
  const groundGeometry = new THREE.PlaneGeometry(200, 200);
  const groundMaterial = new THREE.MeshStandardMaterial({
    color: 0x90_ee_90,
    roughness: 0.8,
  });
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
  ground.rotation.x = -Math.PI / 2;
  ground.receiveShadow = true;
  scene.add(ground);
}

/**
 * 初始化射线检测
 */
function initRaycaster() {
  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2();
}

/**
 * 处理点击事件
 */
function handleClick(event: MouseEvent) {
  if (!containerRef.value) return;

  // 如果有任何弹窗打开，或者正在显示室内组件，则不处理3D场景的点击
  if (
    worshipModalVisible.value ||
    recordModalVisible.value ||
    tabletModalVisible.value ||
    nftModalVisible.value ||
    showInterior.value
  ) {
    return;
  }

  const rect = containerRef.value.getBoundingClientRect();
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(clickableObjects);

  if (intersects.length > 0) {
    const object = intersects[0].object;
    if (object.userData.clickable) {
      handleObjectClick(object.userData.type, object.userData);
    }
  }
}

/**
 * 处理对象点击
 */
function handleObjectClick(type: string, userData?: any) {
  switch (type) {
    case 'door': {
      toggleDoor();
      break;
    }
    case 'incense-burner': {
      audioManager.play('incense');
      message.success('香炉：点击"虚拟祭祀"开始上香仪式');
      break;
    }
    case 'tablet': {
      console.log('点击牌位，userData:', userData);
      if (userData && userData.tabletIndex !== undefined) {
        showTabletDetail(userData.tabletIndex);
      } else {
        message.warning('牌位数据未找到');
      }
      break;
    }
  }
}

/**
 * 更新烟雾粒子动画
 */
function updateSmokeParticles() {
  smokeParticles.forEach((particleSystem) => {
    const positions = particleSystem.geometry.attributes.position
      .array as Float32Array;
    const velocities = particleSystem.userData.velocities as number[];
    const baseY = particleSystem.userData.baseY as number;

    for (let i = 0; i < positions.length / 3; i++) {
      positions[i * 3] += velocities[i * 3];
      positions[i * 3 + 1] += velocities[i * 3 + 1];
      positions[i * 3 + 2] += velocities[i * 3 + 2];

      // 粒子上升到一定高度后重置
      if (positions[i * 3 + 1] > baseY + 3) {
        positions[i * 3] =
          particleSystem.position.x + (Math.random() - 0.5) * 0.2;
        positions[i * 3 + 1] = baseY;
        positions[i * 3 + 2] =
          particleSystem.position.z + (Math.random() - 0.5) * 0.2;
      }
    }

    particleSystem.geometry.attributes.position.needsUpdate = true;
  });
}

/**
 * 打开/关闭祠堂门
 */
function toggleDoor() {
  doorOpen.value = !doorOpen.value;
  audioManager.play('drum');

  if (doorOpen.value) {
    message.success(
      '🚪 祠堂大门正在打开！可以看到5个金色发光的牌位，点击查看详情',
    );

    // 让墙体变透明，可以看到内部
    if (
      shrineWalls &&
      shrineWalls.material instanceof THREE.MeshStandardMaterial
    ) {
      shrineWalls.material.opacity = 0.3;
      shrineWalls.material.needsUpdate = true;
    }

    // 双门打开动画 - 左门向左旋转，右门向右旋转
    if (shrineDoor && shrineDoor.userData.rightDoor) {
      const leftDoor = shrineDoor;
      const rightDoor = shrineDoor.userData.rightDoor;

      // 左门绕左边缘旋转（向左开）
      animateDoorOpen(leftDoor, -Math.PI / 2, -1.5);

      // 右门绕右边缘旋转（向右开）
      animateDoorOpen(rightDoor, Math.PI / 2, 1.5);
    }

    // 隐藏香炉（进入内部后不需要看到外面的香炉）
    if (incenseBurner) {
      incenseBurner.visible = false;
    }

    // 隐藏屋顶，避免进入时先看到屋顶
    if (shrineRoof) {
      shrineRoof.visible = false;
    }

    // 柱子保持可见（室内装饰）
    // shrinePillars.forEach(pillar => {
    //   if (pillar.material instanceof THREE.MeshStandardMaterial) {
    //     pillar.material.opacity = 0.2;
    //     pillar.material.transparent = true;
    //     pillar.material.needsUpdate = true;
    //   }
    // });

    // 门保持可见（室内装饰）
    // if (shrineDoor && shrineDoor.userData.rightDoor) {
    //   const leftDoor = shrineDoor;
    //   const rightDoor = shrineDoor.userData.rightDoor;
    //   if (leftDoor.material instanceof THREE.MeshStandardMaterial) {
    //     leftDoor.material.opacity = 0.1;
    //     leftDoor.material.transparent = true;
    //     leftDoor.material.needsUpdate = true;
    //   }
    //   if (rightDoor.material instanceof THREE.MeshStandardMaterial) {
    //     rightDoor.material.opacity = 0.1;
    //     rightDoor.material.transparent = true;
    //     rightDoor.material.needsUpdate = true;
    //   }
    // }

    // 切换到室内组件
    showInterior.value = true;

    // 禁用自动旋转，方便查看
    if (autoRotate.value) {
      toggleAutoRotate();
    }
  } else {
    message.info('🚪 祠堂大门正在关闭');

    // 恢复墙体不透明
    if (
      shrineWalls &&
      shrineWalls.material instanceof THREE.MeshStandardMaterial
    ) {
      shrineWalls.material.opacity = 1;
      shrineWalls.material.needsUpdate = true;
    }

    // 双门关闭动画 - 恢复到原位
    if (shrineDoor && shrineDoor.userData.rightDoor) {
      const leftDoor = shrineDoor;
      const rightDoor = shrineDoor.userData.rightDoor;

      animateDoorClose(leftDoor, -1.5);
      animateDoorClose(rightDoor, 1.5);
    }

    // 显示香炉（回到外部视角）
    if (incenseBurner) {
      incenseBurner.visible = true;
    }

    // 显示屋顶
    if (shrineRoof) {
      shrineRoof.visible = true;
    }

    // 恢复柱子不透明（如果需要）
    // shrinePillars.forEach(pillar => {
    //   if (pillar.material instanceof THREE.MeshStandardMaterial) {
    //     pillar.material.opacity = 1;
    //     pillar.material.transparent = false;
    //     pillar.material.needsUpdate = true;
    //   }
    // });

    // 恢复门不透明（如果需要）
    // if (shrineDoor && shrineDoor.userData.rightDoor) {
    //   const leftDoor = shrineDoor;
    //   const rightDoor = shrineDoor.userData.rightDoor;
    //   if (leftDoor.material instanceof THREE.MeshStandardMaterial) {
    //     leftDoor.material.opacity = 1;
    //     leftDoor.material.transparent = false;
    //     leftDoor.material.needsUpdate = true;
    //   }
    //   if (rightDoor.material instanceof THREE.MeshStandardMaterial) {
    //     rightDoor.material.opacity = 1;
    //     rightDoor.material.transparent = false;
    //     rightDoor.material.needsUpdate = true;
    //   }
    // }

    // 重置控制器限制
    controls.maxDistance = 100;
    controls.minDistance = 5;
    controls.maxPolarAngle = Math.PI;

    // 重置相机到初始位置
    camera.position.set(0, 10, 30);
    camera.lookAt(0, 5, 0);
    controls.target.set(0, 5, 0);
    controls.update();

    // 切换回3D场景
    showInterior.value = false;
  }
}

/**
 * 门打开动画
 */
function animateDoorOpen(
  door: THREE.Mesh,
  targetRotation: number,
  pivotX: number,
) {
  const duration = 1000; // 1秒
  const startRotation = 0;
  const startTime = Date.now();

  function animate() {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);

    // 使用缓动函数
    const easeProgress = 1 - (1 - progress) ** 3; // easeOutCubic

    // 计算当前旋转角度
    const currentRotation =
      startRotation + (targetRotation - startRotation) * easeProgress;

    // 设置旋转（绕Y轴）
    door.rotation.y = currentRotation;

    // 调整位置，让门绕边缘旋转而不是中心
    const offset = Math.sin(currentRotation) * 1.5;
    door.position.set(pivotX + offset, 6, 6.5 + Math.abs(offset));

    if (progress < 1) {
      requestAnimationFrame(animate);
    }
  }

  animate();
}

/**
 * 门关闭动画
 */
function animateDoorClose(door: THREE.Mesh, pivotX: number) {
  const duration = 1000;
  const startRotation = door.rotation.y;
  const startTime = Date.now();

  function animate() {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);

    const easeProgress = 1 - (1 - progress) ** 3;
    const currentRotation = startRotation + (0 - startRotation) * easeProgress;

    door.rotation.y = currentRotation;
    door.position.set(pivotX, 6, 6.5);

    if (progress < 1) {
      requestAnimationFrame(animate);
    }
  }

  animate();
}

/**
 * 相机移动到室内全景视图
 */
function animateCameraToTablets() {
  const duration = 2500; // 2.5秒，更平滑
  const startTime = Date.now();

  // 起始位置（当前相机位置）
  const startPos = camera.position.clone();
  const startLook = new THREE.Vector3(0, 0, 0);

  // 目标位置（室内中央，全景视角）
  const endPos = new THREE.Vector3(0, 5, 0); // 室内中央，牌位高度
  const endLook = new THREE.Vector3(0, 5, -3); // 看向牌位区域

  // 禁用控制器，避免冲突
  controls.enabled = false;

  function animate() {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);

    // 使用缓动函数
    const easeProgress = 1 - (1 - progress) ** 3;

    // 插值计算当前位置和朝向
    const currentPos = startPos.clone().lerp(endPos, easeProgress);
    const currentLook = startLook.clone().lerp(endLook, easeProgress);

    camera.position.copy(currentPos);
    camera.lookAt(currentLook);

    if (progress < 1) {
      requestAnimationFrame(animate);
    } else {
      // 动画完成后重新启用控制器，但限制范围
      controls.enabled = true;
      controls.target.copy(endLook);

      // 设置控制器的限制，保持在室内
      controls.maxDistance = 8; // 最大距离
      controls.minDistance = 3; // 最小距离
      controls.maxPolarAngle = Math.PI * 0.8; // 限制上下角度
      controls.update();
    }
  }

  animate();
}

/**
 * 相机回到外部视角动画
 */
function animateCameraToExterior() {
  const duration = 1500; // 1.5秒
  const startTime = Date.now();

  // 起始位置（当前相机位置）
  const startPos = camera.position.clone();

  // 目标位置（外部视角）
  const endPos = new THREE.Vector3(0, 30, 50);
  const endLook = new THREE.Vector3(0, 0, 0);

  // 禁用控制器
  controls.enabled = false;

  function animate() {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);

    // 使用缓动函数
    const easeProgress = 1 - (1 - progress) ** 3;

    // 插值计算当前位置
    const currentPos = startPos.clone().lerp(endPos, easeProgress);

    camera.position.copy(currentPos);
    camera.lookAt(endLook);

    if (progress < 1) {
      requestAnimationFrame(animate);
    } else {
      // 动画完成后重新启用控制器
      controls.enabled = true;
      controls.target.copy(endLook);
      controls.update();
    }
  }

  animate();
}

/**
 * 显示牌位详情
 */
function showTabletDetail(index: number) {
  console.log('显示牌位详情，index:', index, '总数:', tablets.value.length);
  const tablet = tablets.value[index];
  if (tablet) {
    console.log('找到牌位:', tablet);
    selectedTablet.value = tablet;
    tabletModalVisible.value = true;
    audioManager.play('bell');
    message.success(`查看 ${tablet.name} 的牌位信息`);
  } else {
    console.error('未找到牌位，index:', index);
    message.error('未找到牌位信息');
  }
}

/**
 * 祭拜指定祖先
 */
function worshipThisAncestor(tablet: any) {
  tabletModalVisible.value = false;

  // 找到对应的ancestor
  const ancestor = ancestors.value.find((a) => a.name === tablet.name);
  if (ancestor) {
    selectedAncestor.value = ancestor.id;
  }

  startWorship();
}

/**
 * 查看族谱关系
 */
function viewFamilyTree(tablet: any) {
  message.info(`即将跳转到族谱页面，查看${tablet.name}的家族关系树`);
  tabletModalVisible.value = false;
}

// 退出室内组件
function exitInterior() {
  // 关闭门并恢复外部场景
  if (doorOpen.value) {
    toggleDoor(); // 这会自动设置 showInterior.value = false 并恢复场景
  } else {
    showInterior.value = false;
    message.info('已退出祠堂内部');
  }
}

/**
 * 获取祖先名称
 */
function getAncestorName() {
  const ancestor = ancestors.value.find((a) => a.id === selectedAncestor.value);
  return ancestor ? ancestor.name : '';
}

/**
 * 获取祭品文本
 */
function getOfferingsText() {
  return selectedOfferings.value
    .map((id) => offerings.find((o) => o.id === id)?.name || '')
    .join('、');
}

/**
 * 格式化时间
 */
function formatTime(time: string) {
  return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
}

/**
 * 动画循环
 */
function animate() {
  animationId = requestAnimationFrame(animate);

  // 更新烟雾粒子
  updateSmokeParticles();

  // 更新天气效果
  updateWeatherEffect();

  controls.update();
  renderer.render(scene, camera);
}

/**
 * 重置相机
 */
function resetCamera() {
  camera.position.set(0, 30, 50);
  camera.lookAt(0, 0, 0);
  controls.reset();
  message.success('视角已重置');
}

/**
 * 切换主题
 */
function toggleTheme() {
  const themes: Array<'ming' | 'qing' | 'song'> = ['song', 'ming', 'qing'];
  const currentIndex = themes.indexOf(currentTheme.value);
  const nextIndex = (currentIndex + 1) % themes.length;
  currentTheme.value = themes[nextIndex];

  // 更换材质颜色
  const colors = {
    song: 0x87_ce_eb, // 宋朝青蓝
    ming: 0xff_6b_6b, // 明朝红
    qing: 0xff_d7_00, // 清朝金
  };

  shrine.children.forEach((child) => {
    if (
      child instanceof THREE.Mesh &&
      child.material instanceof THREE.MeshStandardMaterial &&
      child.geometry instanceof THREE.BoxGeometry &&
      child.position.y > 5
    ) {
      child.material.color.setHex(colors[currentTheme.value]);
    }
  });

  message.success(
    `已切换为${currentTheme.value === 'ming' ? '明朝' : currentTheme.value === 'qing' ? '清朝' : '宋朝'}风格`,
  );
}

/**
 * 切换自动旋转
 */
function toggleAutoRotate() {
  autoRotate.value = !autoRotate.value;
  controls.autoRotate = autoRotate.value;
}

/**
 * 检查当前节日
 */
function checkFestival() {
  const today = dayjs();
  const month = today.month() + 1;
  const day = today.date();

  // 检查传统节日
  if (month === 1 && day === 1) {
    festival.value = '🎊 春节';
    showFestivalDecoration.value = true;
    addSpringFestivalDecoration();
  } else if (month === 4 && day === 4) {
    festival.value = '🌸 清明节';
    showFestivalDecoration.value = true;
  } else if (month === 9 && day === 9) {
    festival.value = '🍂 重阳节';
    showFestivalDecoration.value = true;
  } else if (month === 8 && day === 15) {
    festival.value = '🌕 中秋节';
    showFestivalDecoration.value = true;
  }
}

/**
 * 添加春节装饰
 */
function addSpringFestivalDecoration() {
  if (!shrine) return;

  // 添加灯笼
  const positions = [
    [-10, 12, 7],
    [10, 12, 7],
    [-10, 12, -7],
    [10, 12, -7],
  ];

  positions.forEach(([x, y, z]) => {
    const lanternGeometry = new THREE.SphereGeometry(0.8, 16, 16);
    const lanternMaterial = new THREE.MeshStandardMaterial({
      color: 0xff_00_00,
      emissive: 0xff_66_00,
      emissiveIntensity: 0.5,
    });
    const lantern = new THREE.Mesh(lanternGeometry, lanternMaterial);
    lantern.position.set(x, y, z);
    shrine.add(lantern);
  });

  message.info('🎊 春节快乐！已添加节日装饰');
}

/**
 * 开始祭祀
 */
function startWorship() {
  audioManager.play('bell');
  worshipStep.value = 0;
  selectedAncestor.value = '';
  selectedOfferings.value = [];
  worshipData.value = {
    title: '',
    content: '',
    onChain: true,
  };
  worshipModalVisible.value = true;
}

/**
 * 提交祭祀
 */
async function submitWorship() {
  submitting.value = true;

  // 模拟上链
  await new Promise((resolve) => setTimeout(resolve, 2000));

  const ancestorInfo = ancestors.value.find(
    (a) => a.id === selectedAncestor.value,
  );
  const ancestorName = ancestorInfo?.name || '';

  // 添加到记录
  worshipRecords.value.unshift({
    id: Date.now(),
    ancestorName,
    ancestorAvatar: ancestorInfo?.avatar || '',
    title: worshipData.value.title || '虚拟祭祀',
    offerings: selectedOfferings.value.map(
      (id) => offerings.find((o) => o.id === id)?.name || '',
    ),
    content: worshipData.value.content,
    time: new Date().toISOString(),
    sbtMinted: worshipData.value.onChain,
    sbtTokenId: worshipData.value.onChain
      ? `SBT-${4000 + worshipRecords.value.length}`
      : '',
  });

  submitting.value = false;
  worshipModalVisible.value = false;

  // 播放祭祀完成音效
  audioManager.play('prayer');

  // 检查是否选择了烟花或鞭炮，触发特效
  const hasFireworks = selectedOfferings.value.some((id) =>
    ['fireworks', 'fireworks-dragon', 'fireworks-luxury'].includes(id),
  );
  const hasFirecracker = selectedOfferings.value.includes('firecracker');

  if (hasFireworks) {
    triggerFireworks();
    message.success('🎆 烟花盛放，祭祀圆满！');
  }

  if (hasFirecracker) {
    triggerFirecracker();
    message.success('🧨 鞭炮齐鸣，祈福平安！');
  }

  if (worshipData.value.onChain) {
    message.success(
      `祭祀完成！已生成祭礼SBT #${4000 + worshipRecords.value.length}`,
    );
  } else if (!hasFireworks && !hasFirecracker) {
    message.success('祭祀完成！');
  }
}

/**
 * 查看祭祀记录
 */
function viewRecords() {
  recordModalVisible.value = true;
}

/**
 * 查看NFT墙
 */
function viewNFTWall() {
  nftModalVisible.value = true;
}

/**
 * 切换天气
 */
function toggleWeather() {
  const weathers: Array<'rain' | 'snow' | 'sunny'> = ['sunny', 'rain', 'snow'];
  const currentIndex = weathers.indexOf(weatherEffect.value);
  const nextIndex = (currentIndex + 1) % weathers.length;
  weatherEffect.value = weathers[nextIndex];

  // 移除现有天气效果
  if (rainParticles) {
    scene.remove(rainParticles);
    rainParticles = null;
  }
  if (snowParticles) {
    scene.remove(snowParticles);
    snowParticles = null;
  }

  // 添加新天气效果和环境音效
  audioManager.stopAllAmbient();

  if (weatherEffect.value === 'rain') {
    createRainEffect();
    scene.background = new THREE.Color(0x60_60_60);
    audioManager.playAmbient('rain');
    message.info('切换为雨天');
  } else if (weatherEffect.value === 'snow') {
    createSnowEffect();
    scene.background = new THREE.Color(0xcc_cc_cc);
    audioManager.playAmbient('wind');
    message.info('切换为雪天');
  } else {
    scene.background = new THREE.Color(0x87_ce_eb);
    if (timeOfDay.value === 'day') {
      audioManager.playAmbient('birds');
    }
    message.info('切换为晴天');
  }
}

/**
 * 创建雨效果
 */
function createRainEffect() {
  const particleCount = 1000;
  const particles = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    positions[i * 3] = (Math.random() - 0.5) * 100;
    positions[i * 3 + 1] = Math.random() * 50;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));

  const particleMaterial = new THREE.PointsMaterial({
    color: 0x64_95_ed,
    size: 0.1,
    transparent: true,
    opacity: 0.6,
  });

  rainParticles = new THREE.Points(particles, particleMaterial);
  scene.add(rainParticles);
}

/**
 * 创建雪效果
 */
function createSnowEffect() {
  const particleCount = 500;
  const particles = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    positions[i * 3] = (Math.random() - 0.5) * 100;
    positions[i * 3 + 1] = Math.random() * 50;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));

  const particleMaterial = new THREE.PointsMaterial({
    color: 0xff_ff_ff,
    size: 0.3,
    transparent: true,
    opacity: 0.8,
  });

  snowParticles = new THREE.Points(particles, particleMaterial);
  scene.add(snowParticles);
}

/**
 * 更新天气效果
 */
function updateWeatherEffect() {
  if (rainParticles) {
    const positions = rainParticles.geometry.attributes.position
      .array as Float32Array;
    for (let i = 0; i < positions.length / 3; i++) {
      positions[i * 3 + 1] -= 0.5;
      if (positions[i * 3 + 1] < 0) {
        positions[i * 3 + 1] = 50;
      }
    }
    rainParticles.geometry.attributes.position.needsUpdate = true;
  }

  if (snowParticles) {
    const positions = snowParticles.geometry.attributes.position
      .array as Float32Array;
    for (let i = 0; i < positions.length / 3; i++) {
      positions[i * 3 + 1] -= 0.1;
      positions[i * 3] += Math.sin(Date.now() * 0.001 + i) * 0.02;
      if (positions[i * 3 + 1] < 0) {
        positions[i * 3 + 1] = 50;
      }
    }
    snowParticles.geometry.attributes.position.needsUpdate = true;
  }
}

/**
 * 切换昼夜
 */
function toggleTimeOfDay() {
  timeOfDay.value = timeOfDay.value === 'day' ? 'night' : 'day';

  audioManager.stopAllAmbient();

  if (timeOfDay.value === 'night') {
    // 夜晚模式
    scene.background = new THREE.Color(0x00_00_33);
    scene.fog = new THREE.Fog(0x00_00_33, 50, 200);
    directionalLight.intensity = 0.3;
    directionalLight.color.setHex(0x88_88_ff);
    audioManager.playAmbient('cricket'); // 夜晚虫鸣
    message.info('切换为夜晚');
  } else {
    // 白天模式
    if (weatherEffect.value === 'sunny') {
      scene.background = new THREE.Color(0x87_ce_eb);
      audioManager.playAmbient('birds'); // 白天鸟鸣
    }
    scene.fog = new THREE.Fog(scene.background.getHex(), 50, 200);
    directionalLight.intensity = 1;
    directionalLight.color.setHex(0xff_ff_ff);
    message.info('切换为白天');
  }
}

/**
 * 鞭炮特效
 */
function triggerFirecracker() {
  // 播放鞭炮音效（使用鼓声模拟）
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      audioManager.play('drum');
    }, i * 100);
  }

  // 创建鞭炮粒子效果
  const particleCount = 200;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const colors = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    // 从地面向上爆炸
    positions[i * 3] = (Math.random() - 0.5) * 10;
    positions[i * 3 + 1] = 2;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 10;

    // 红色为主
    colors[i * 3] = 1;
    colors[i * 3 + 1] = Math.random() * 0.3;
    colors[i * 3 + 2] = 0;
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 0.5,
    vertexColors: true,
    transparent: true,
    opacity: 1,
  });

  const firecrackerParticles = new THREE.Points(geometry, material);
  scene.add(firecrackerParticles);

  // 动画：粒子向上飞散并消失
  let frame = 0;
  const animateFirecracker = () => {
    frame++;
    const positions = firecrackerParticles.geometry.attributes.position
      .array as Float32Array;

    for (let i = 0; i < particleCount; i++) {
      positions[i * 3 + 1] += 0.3; // 向上
      positions[i * 3] += (Math.random() - 0.5) * 0.2; // 左右飘散
      positions[i * 3 + 2] += (Math.random() - 0.5) * 0.2; // 前后飘散
    }

    firecrackerParticles.geometry.attributes.position.needsUpdate = true;
    material.opacity = Math.max(0, 1 - frame / 60);

    if (frame < 60) {
      requestAnimationFrame(animateFirecracker);
    } else {
      scene.remove(firecrackerParticles);
      firecrackerParticles.geometry.dispose();
      material.dispose();
    }
  };

  animateFirecracker();
}

/**
 * 烟花特效
 */
function triggerFireworks() {
  // 播放钟声作为烟花音效
  audioManager.play('bell');

  // 创建3-5次烟花爆炸
  const fireworkCount = 3 + Math.floor(Math.random() * 3);

  for (let f = 0; f < fireworkCount; f++) {
    setTimeout(() => {
      createFireworkExplosion();
    }, f * 800);
  }
}

/**
 * 创建单次烟花爆炸
 */
function createFireworkExplosion() {
  const particleCount = 500;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const velocities: number[] = [];
  const colors = new Float32Array(particleCount * 3);

  // 随机爆炸位置（祠堂上方）
  const explodeX = (Math.random() - 0.5) * 30;
  const explodeY = 20 + Math.random() * 10;
  const explodeZ = (Math.random() - 0.5) * 30;

  // 随机颜色（金、红、蓝、绿、紫、白）
  const colorPalette = [
    [1, 0.84, 0], // 金色
    [1, 0, 0], // 红色
    [0, 0.5, 1], // 蓝色
    [0, 1, 0.5], // 绿色
    [1, 0, 1], // 紫色
    [1, 1, 1], // 白色
  ];
  const selectedColor =
    colorPalette[Math.floor(Math.random() * colorPalette.length)];

  for (let i = 0; i < particleCount; i++) {
    // 初始位置在爆炸点
    positions[i * 3] = explodeX;
    positions[i * 3 + 1] = explodeY;
    positions[i * 3 + 2] = explodeZ;

    // 随机速度（球形爆炸）
    const theta = Math.random() * Math.PI * 2;
    const phi = Math.random() * Math.PI;
    const speed = 0.3 + Math.random() * 0.5;

    velocities.push(
      Math.sin(phi) * Math.cos(theta) * speed,
      Math.cos(phi) * speed,
      Math.sin(phi) * Math.sin(theta) * speed,
    );

    // 颜色（带一些随机变化）
    colors[i * 3] = selectedColor[0] * (0.8 + Math.random() * 0.2);
    colors[i * 3 + 1] = selectedColor[1] * (0.8 + Math.random() * 0.2);
    colors[i * 3 + 2] = selectedColor[2] * (0.8 + Math.random() * 0.2);
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 0.8,
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending, // 发光效果
  });

  const fireworkParticles = new THREE.Points(geometry, material);
  scene.add(fireworkParticles);

  // 动画：粒子爆炸并下落
  let frame = 0;
  const animateFirework = () => {
    frame++;
    const positions = fireworkParticles.geometry.attributes.position
      .array as Float32Array;

    for (let i = 0; i < particleCount; i++) {
      // 根据速度更新位置
      positions[i * 3] += velocities[i * 3];
      positions[i * 3 + 1] += velocities[i * 3 + 1];
      positions[i * 3 + 2] += velocities[i * 3 + 2];

      // 重力效果
      velocities[i * 3 + 1] -= 0.02;
    }

    fireworkParticles.geometry.attributes.position.needsUpdate = true;

    // 渐渐消失
    material.opacity = Math.max(0, 1 - frame / 100);

    if (frame < 100) {
      requestAnimationFrame(animateFirework);
    } else {
      scene.remove(fireworkParticles);
      fireworkParticles.geometry.dispose();
      material.dispose();
    }
  };

  animateFirework();
}

/**
 * 皇家礼炮特效（超级豪华版）
 */
function triggerRoyalSalute() {
  // 播放多次钟声
  for (let i = 0; i < 3; i++) {
    setTimeout(() => {
      audioManager.play('bell');
    }, i * 500);
  }

  // 创建10次烟花爆炸，更密集
  const fireworkCount = 10;

  for (let f = 0; f < fireworkCount; f++) {
    setTimeout(() => {
      // 每次爆炸2个烟花（左右对称）
      createFireworkExplosion();
      setTimeout(() => {
        createFireworkExplosion();
      }, 200);
    }, f * 600);
  }

  message.success('🎇 皇家礼炮燃放！盛世繁华，祈福万代！');
}

/**
 * 金龙烟花特效 - 龙形轨迹烟花
 */
function triggerDragonFirework() {
  audioManager.play('bell');
  message.success('🐉 金龙腾空！龙形烟花绽放！');

  // 创建龙形轨迹路径（S形）
  const dragonPath: Array<[number, number, number]> = [];
  const segments = 50;

  for (let i = 0; i <= segments; i++) {
    const t = i / segments;
    const x = Math.sin(t * Math.PI * 4) * 20; // S形左右摆动
    const y = 10 + t * 20; // 向上飞升
    const z = Math.cos(t * Math.PI * 2) * 10; // 前后波动
    dragonPath.push([x, y, z]);
  }

  // 沿路径释放金色粒子
  dragonPath.forEach((pos, index) => {
    setTimeout(() => {
      createGoldenTrail(pos[0], pos[1], pos[2]);
    }, index * 50);
  });

  // 最后在龙头位置大爆炸
  setTimeout(
    () => {
      const lastPos = dragonPath[dragonPath.length - 1];
      createMassiveGoldenExplosion(lastPos[0], lastPos[1], lastPos[2]);
    },
    segments * 50 + 500,
  );
}

/**
 * 创建金色轨迹粒子
 */
function createGoldenTrail(x: number, y: number, z: number) {
  const particleCount = 30;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const colors = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    positions[i * 3] = x + (Math.random() - 0.5) * 2;
    positions[i * 3 + 1] = y + (Math.random() - 0.5) * 2;
    positions[i * 3 + 2] = z + (Math.random() - 0.5) * 2;

    // 金色
    colors[i * 3] = 1;
    colors[i * 3 + 1] = 0.84 + Math.random() * 0.16;
    colors[i * 3 + 2] = Math.random() * 0.3;
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 1.5,
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending,
  });

  const trail = new THREE.Points(geometry, material);
  scene.add(trail);

  // 淡出
  let frame = 0;
  const fadeOut = () => {
    frame++;
    material.opacity = Math.max(0, 1 - frame / 30);
    if (frame < 30) {
      requestAnimationFrame(fadeOut);
    } else {
      scene.remove(trail);
      trail.geometry.dispose();
      material.dispose();
    }
  };
  fadeOut();
}

/**
 * 创建大型金色爆炸
 */
function createMassiveGoldenExplosion(x: number, y: number, z: number) {
  const particleCount = 2000;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const velocities: number[] = [];
  const colors = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    positions[i * 3] = x;
    positions[i * 3 + 1] = y;
    positions[i * 3 + 2] = z;

    const theta = Math.random() * Math.PI * 2;
    const phi = Math.random() * Math.PI;
    const speed = 0.5 + Math.random() * 1;

    velocities.push(
      Math.sin(phi) * Math.cos(theta) * speed,
      Math.cos(phi) * speed,
      Math.sin(phi) * Math.sin(theta) * speed,
    );

    // 金红色混合
    colors[i * 3] = 1;
    colors[i * 3 + 1] = 0.5 + Math.random() * 0.5;
    colors[i * 3 + 2] = Math.random() * 0.3;
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 1.2,
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending,
  });

  const explosion = new THREE.Points(geometry, material);
  scene.add(explosion);

  let frame = 0;
  const animate = () => {
    frame++;
    const positions = explosion.geometry.attributes.position
      .array as Float32Array;

    for (let i = 0; i < particleCount; i++) {
      positions[i * 3] += velocities[i * 3];
      positions[i * 3 + 1] += velocities[i * 3 + 1];
      positions[i * 3 + 2] += velocities[i * 3 + 2];
      velocities[i * 3 + 1] -= 0.02;
    }

    explosion.geometry.attributes.position.needsUpdate = true;
    material.opacity = Math.max(0, 1 - frame / 120);

    if (frame < 120) {
      requestAnimationFrame(animate);
    } else {
      scene.remove(explosion);
      explosion.geometry.dispose();
      material.dispose();
    }
  };

  animate();
}

/**
 * 花瓣飘落特效
 */
function triggerFlowerRain() {
  audioManager.play('bell');
  message.success('🌸 花瓣飘落，芬芳满堂！');

  const petalCount = 1000;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(petalCount * 3);
  const velocities: number[] = [];
  const colors = new Float32Array(petalCount * 3);

  const petalColors = [
    [1, 0.75, 0.8], // 粉色
    [1, 1, 1], // 白色
    [1, 0.4, 0.7], // 玫红
    [1, 0.9, 0.9], // 浅粉
  ];

  for (let i = 0; i < petalCount; i++) {
    // 从高空随机位置开始
    positions[i * 3] = (Math.random() - 0.5) * 50;
    positions[i * 3 + 1] = 30 + Math.random() * 10;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 50;

    // 下落速度（带一些横向飘动）
    velocities.push(
      (Math.random() - 0.5) * 0.1, // x轻微飘动
      -0.1 - Math.random() * 0.1, // y向下
      (Math.random() - 0.5) * 0.1, // z轻微飘动
    );

    // 随机花瓣颜色
    const color = petalColors[Math.floor(Math.random() * petalColors.length)];
    colors[i * 3] = color[0];
    colors[i * 3 + 1] = color[1];
    colors[i * 3 + 2] = color[2];
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 1.5,
    vertexColors: true,
    transparent: true,
    opacity: 0.9,
  });

  const petals = new THREE.Points(geometry, material);
  scene.add(petals);

  let frame = 0;
  const animate = () => {
    frame++;
    const positions = petals.geometry.attributes.position.array as Float32Array;

    for (let i = 0; i < petalCount; i++) {
      positions[i * 3] += velocities[i * 3];
      positions[i * 3 + 1] += velocities[i * 3 + 1];
      positions[i * 3 + 2] += velocities[i * 3 + 2];

      // 螺旋飘落
      velocities[i * 3] += Math.sin(frame * 0.1 + i) * 0.01;
      velocities[i * 3 + 2] += Math.cos(frame * 0.1 + i) * 0.01;

      // 落到地面后重置到顶部（循环）
      if (positions[i * 3 + 1] < 0) {
        positions[i * 3 + 1] = 40;
      }
    }

    petals.geometry.attributes.position.needsUpdate = true;

    if (frame < 300) {
      requestAnimationFrame(animate);
    } else {
      scene.remove(petals);
      petals.geometry.dispose();
      material.dispose();
    }
  };

  animate();
}

/**
 * 金光普照特效
 */
function triggerGoldenLight() {
  audioManager.play('bell');
  message.success('✨ 金光普照，福泽万代！');

  // 从祠堂中心向外放射金光
  const rayCount = 50;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(rayCount * 2 * 3); // 每条光线2个点
  const colors = new Float32Array(rayCount * 2 * 3);

  for (let i = 0; i < rayCount; i++) {
    const angle = (i / rayCount) * Math.PI * 2;

    // 起点（祠堂中心）
    positions[i * 6] = 0;
    positions[i * 6 + 1] = 10;
    positions[i * 6 + 2] = 0;

    // 终点（向外放射）
    positions[i * 6 + 3] = Math.cos(angle) * 50;
    positions[i * 6 + 4] = 10 + Math.sin(i) * 10;
    positions[i * 6 + 5] = Math.sin(angle) * 50;

    // 金色
    for (let j = 0; j < 2; j++) {
      colors[(i * 2 + j) * 3] = 1;
      colors[(i * 2 + j) * 3 + 1] = 0.84;
      colors[(i * 2 + j) * 3 + 2] = 0;
    }
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.LineBasicMaterial({
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending,
  });

  const rays = new THREE.LineSegments(geometry, material);
  scene.add(rays);

  // 脉冲动画
  let frame = 0;
  const pulse = () => {
    frame++;
    const scale = 1 + Math.sin(frame * 0.1) * 0.3;
    rays.scale.set(scale, 1, scale);
    material.opacity = Math.max(0, 1 - frame / 150);

    if (frame < 150) {
      requestAnimationFrame(pulse);
    } else {
      scene.remove(rays);
      rays.geometry.dispose();
      material.dispose();
    }
  };

  pulse();
}

/**
 * 文字烟花特效 - 显示"朱氏万代"
 */
function triggerTextFirework() {
  audioManager.play('bell');
  message.success('📝 文字烟花："朱氏万代"！');

  const text = '朱氏万代';
  const charPositions = [
    [-15, 25, 0], // 朱
    [-5, 25, 0], // 氏
    [5, 25, 0], // 万
    [15, 25, 0], // 代
  ];

  charPositions.forEach((pos, index) => {
    setTimeout(() => {
      createCharacterFirework(text[index], pos[0], pos[1], pos[2]);
    }, index * 500);
  });
}

/**
 * 创建单个文字烟花
 */
function createCharacterFirework(
  char: string,
  x: number,
  y: number,
  z: number,
) {
  // 简化版：用粒子拼出字的轮廓
  const particleCount = 200;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const colors = new Float32Array(particleCount * 3);

  // 创建字形轮廓（简化为圆形）
  for (let i = 0; i < particleCount; i++) {
    const angle = (i / particleCount) * Math.PI * 2;
    const radius = 3;

    positions[i * 3] = x + Math.cos(angle) * radius;
    positions[i * 3 + 1] = y + Math.sin(angle) * radius;
    positions[i * 3 + 2] = z;

    // 金色
    colors[i * 3] = 1;
    colors[i * 3 + 1] = 0.84;
    colors[i * 3 + 2] = 0;
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 1.5,
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending,
  });

  const charShape = new THREE.Points(geometry, material);
  scene.add(charShape);

  // 保持一段时间后消失
  let frame = 0;
  const stay = () => {
    frame++;
    material.opacity = frame < 60 ? 1 : Math.max(0, 1 - (frame - 60) / 60);

    if (frame < 120) {
      requestAnimationFrame(stay);
    } else {
      scene.remove(charShape);
      charShape.geometry.dispose();
      material.dispose();
    }
  };

  stay();
}

/**
 * 凤凰涅槃特效
 */
function triggerPhoenixRising() {
  audioManager.play('bell');
  message.success('🔥 凤凰涅槃，浴火重生！');

  // 从地面升起的火焰粒子
  const particleCount = 1500;
  const geometry = new THREE.BufferGeometry();
  const positions = new Float32Array(particleCount * 3);
  const velocities: number[] = [];
  const colors = new Float32Array(particleCount * 3);

  for (let i = 0; i < particleCount; i++) {
    // 从祠堂中心地面开始
    positions[i * 3] = (Math.random() - 0.5) * 5;
    positions[i * 3 + 1] = 0;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 5;

    // 螺旋向上的速度
    const angle = Math.random() * Math.PI * 2;
    velocities.push(
      Math.cos(angle) * 0.2, // x
      0.5 + Math.random() * 0.5, // y向上
      Math.sin(angle) * 0.2, // z
    );

    // 火焰色（红→橙→黄渐变）
    const heat = Math.random();
    colors[i * 3] = 1;
    colors[i * 3 + 1] = heat * 0.5;
    colors[i * 3 + 2] = heat * 0.2;
  }

  geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

  const material = new THREE.PointsMaterial({
    size: 1,
    vertexColors: true,
    transparent: true,
    opacity: 1,
    blending: THREE.AdditiveBlending,
  });

  const phoenix = new THREE.Points(geometry, material);
  scene.add(phoenix);

  let frame = 0;
  const animate = () => {
    frame++;
    const positions = phoenix.geometry.attributes.position
      .array as Float32Array;

    for (let i = 0; i < particleCount; i++) {
      positions[i * 3] += velocities[i * 3];
      positions[i * 3 + 1] += velocities[i * 3 + 1];
      positions[i * 3 + 2] += velocities[i * 3 + 2];

      // 螺旋效果
      const angle = frame * 0.05 + i * 0.1;
      velocities[i * 3] = Math.cos(angle) * 0.2;
      velocities[i * 3 + 2] = Math.sin(angle) * 0.2;

      // 到顶部后爆炸
      if (positions[i * 3 + 1] > 25) {
        velocities[i * 3] *= 3;
        velocities[i * 3 + 1] = -0.3;
        velocities[i * 3 + 2] *= 3;
      }
    }

    phoenix.geometry.attributes.position.needsUpdate = true;
    material.opacity = Math.max(0, 1 - frame / 200);

    if (frame < 200) {
      requestAnimationFrame(animate);
    } else {
      scene.remove(phoenix);
      phoenix.geometry.dispose();
      material.dispose();
    }
  };

  animate();
}

/**
 * 全特效组合 - 终极演示
 */
function triggerAllEffects() {
  message.success('🌈 全特效组合！盛世华章！');

  // 依次触发所有特效
  triggerGoldenLight();

  setTimeout(() => {
    triggerFlowerRain();
  }, 500);

  setTimeout(() => {
    triggerDragonFirework();
  }, 1000);

  setTimeout(() => {
    triggerFireworks();
  }, 2000);

  setTimeout(() => {
    triggerRoyalSalute();
  }, 3000);

  setTimeout(() => {
    triggerPhoenixRising();
  }, 4000);

  setTimeout(() => {
    triggerFirecracker();
  }, 5000);

  setTimeout(() => {
    triggerTextFirework();
  }, 6000);
}

/**
 * 处理窗口大小改变
 */
function handleResize() {
  const width = containerRef.value!.clientWidth;
  const height = containerRef.value!.clientHeight;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  renderer.setSize(width, height);
}
</script>

<template>
  <div class="virtual-shrine-3d">
    <!-- 室内组件 -->
    <InteriorShrine v-show="showInterior" @exit="exitInterior" />

    <!-- 3D场景容器 -->
    <div
      v-show="!showInterior"
      ref="containerRef"
      class="shrine-container"
    ></div>

    <!-- 控制面板 -->
    <div v-if="!showInterior" class="controls-panel">
      <a-space direction="vertical">
        <a-space>
          <a-button @click="resetCamera"> <AimOutlined /> 重置视角 </a-button>
          <a-button @click="toggleTheme">
            <SkinOutlined />
            {{
              currentTheme === 'ming'
                ? '明朝'
                : currentTheme === 'qing'
                  ? '清朝'
                  : '宋朝'
            }}风格
          </a-button>
          <a-button
            @click="toggleDoor"
            :type="doorOpen ? 'primary' : 'default'"
          >
            {{ doorOpen ? '🚪 关闭祠堂门' : '🚪 打开祠堂门' }}
          </a-button>
          <a-button @click="toggleAutoRotate">
            <SyncOutlined :spin="autoRotate" />
            {{ autoRotate ? '停止' : '开始' }}旋转
          </a-button>
          <a-button @click="toggleWeather">
            <CloudOutlined />
            {{
              weatherEffect === 'sunny'
                ? '晴天'
                : weatherEffect === 'rain'
                  ? '雨天'
                  : '雪天'
            }}
          </a-button>
          <a-button @click="toggleTimeOfDay">
            {{ timeOfDay === 'day' ? '🌞' : '🌙' }}
            {{ timeOfDay === 'day' ? '白天' : '夜晚' }}
          </a-button>
        </a-space>
        <a-space>
          <a-button type="primary" @click="startWorship">
            <FireOutlined /> 虚拟祭祀
          </a-button>
          <a-button @click="viewRecords">
            <HistoryOutlined /> 祭祀记录
          </a-button>
          <a-button @click="viewNFTWall">
            <PictureOutlined /> NFT展示墙
          </a-button>
        </a-space>
        <a-space>
          <a-button type="primary" danger @click="triggerFirecracker">
            🧨 燃放鞭炮
          </a-button>
          <a-button
            type="primary"
            @click="triggerFireworks"
            style="
              background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
              border: none;
            "
          >
            🎆 燃放烟花
          </a-button>
          <a-button
            type="primary"
            @click="triggerRoyalSalute"
            style="
              background: linear-gradient(45deg, #f093fb 0%, #f5576c 100%);
              border: none;
            "
          >
            🎇 皇家礼炮
          </a-button>
        </a-space>
      </a-space>
    </div>

    <!-- 帮助提示 -->
    <div v-if="!showInterior" class="help-panel">
      <a-alert type="info" closable>
        <template #message>
          <div class="help-content">
            <span>🖱️ <b>左键拖拽</b>: 旋转视角</span>
            <span>🔍 <b>滚轮</b>: 缩放</span>
            <span>👆 <b>右键拖拽</b>: 平移</span>
            <span>🚪 <b>点击门</b>: 打开/关闭</span>
            <span>🏛️ <b>点击牌位</b>: 查看详情</span>
          </div>
        </template>
      </a-alert>
    </div>

    <!-- 状态面板 -->
    <div v-if="!showInterior" class="status-panel">
      <a-space direction="vertical" :size="8">
        <a-tag color="green"> <TeamOutlined /> {{ onlineUsers }}人在线 </a-tag>
        <a-tag v-if="festival" color="red">
          {{ festival }}
        </a-tag>
        <a-tag color="blue">
          {{
            weatherEffect === 'sunny'
              ? '☀️ 晴'
              : weatherEffect === 'rain'
                ? '🌧️ 雨'
                : '❄️ 雪'
          }}
          {{ timeOfDay === 'day' ? '🌞' : '🌙' }}
        </a-tag>
      </a-space>
    </div>

    <!-- 特效演示面板（右侧） -->
    <div v-if="!showInterior" class="effects-demo-panel">
      <a-card title="✨ 特效演示" size="small" :bordered="true">
        <a-space direction="vertical" style="width: 100%" :size="8">
          <!-- 基础特效 -->
          <div class="effect-category">
            <div class="category-title">🎆 庆典烟火</div>
            <a-button
              size="small"
              type="primary"
              danger
              block
              @click="triggerFirecracker"
            >
              🧨 鞭炮齐鸣
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerFireworks"
              style="
                color: white;
                background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
                border: none;
              "
            >
              🎆 烟花盛宴
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerRoyalSalute"
              style="
                color: white;
                background: linear-gradient(45deg, #f093fb 0%, #f5576c 100%);
                border: none;
              "
            >
              🎇 皇家礼炮
            </a-button>
          </div>

          <!-- 高级特效 -->
          <div class="effect-category">
            <div class="category-title">💎 高级特效</div>
            <a-button
              size="small"
              block
              @click="triggerDragonFirework"
              style="
                color: white;
                background: linear-gradient(45deg, #ffd700 0%, #ffa500 100%);
                border: none;
              "
            >
              🐉 金龙烟花
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerFlowerRain"
              style="
                color: white;
                background: linear-gradient(45deg, #ff69b4 0%, #ff1493 100%);
                border: none;
              "
            >
              🌸 花瓣飘落
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerGoldenLight"
              style="
                color: white;
                background: linear-gradient(45deg, #ffd700 0%, #daa520 100%);
                border: none;
              "
            >
              ✨ 金光普照
            </a-button>
          </div>

          <!-- VIP特效 -->
          <div class="effect-category">
            <div class="category-title">👑 VIP特效</div>
            <a-button
              size="small"
              block
              @click="triggerTextFirework"
              style="
                color: white;
                background: linear-gradient(45deg, #8e2de2 0%, #4a00e0 100%);
                border: none;
              "
            >
              📝 文字烟花
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerPhoenixRising"
              style="
                color: white;
                background: linear-gradient(45deg, #ff4e50 0%, #f9d423 100%);
                border: none;
              "
            >
              🔥 凤凰涅槃
            </a-button>
            <a-button
              size="small"
              block
              @click="triggerAllEffects"
              style="
                color: white;
                background: linear-gradient(
                  45deg,
                  #ff0080 0%,
                  #7928ca 50%,
                  #0070f3 100%
                );
                border: none;
              "
            >
              🌈 全特效组合
            </a-button>
          </div>
        </a-space>
      </a-card>
    </div>

    <!-- 虚拟祭祀Modal -->
    <a-modal
      v-model:open="worshipModalVisible"
      title="🙏 虚拟祭祀"
      width="1200px"
      :body-style="{ maxHeight: '70vh', overflowY: 'auto' }"
    >
      <a-steps :current="worshipStep">
        <a-step title="选择祖先" />
        <a-step title="选择祭品" />
        <a-step title="撰写祭文" />
        <a-step title="完成祭祀" />
      </a-steps>

      <div style="margin-top: 24px">
        <!-- 步骤1: 选择祖先 -->
        <div v-if="worshipStep === 0">
          <h4>选择要祭拜的祖先</h4>
          <a-radio-group v-model:value="selectedAncestor" style="width: 100%">
            <a-space direction="vertical" style="width: 100%">
              <a-radio
                v-for="ancestor in ancestors"
                :key="ancestor.id"
                :value="ancestor.id"
              >
                <a-space>
                  <a-avatar :src="ancestor.avatar" />
                  <span>{{ ancestor.name }} - {{ ancestor.title }}</span>
                </a-space>
              </a-radio>
            </a-space>
          </a-radio-group>
        </div>

        <!-- 步骤2: 选择祭品 -->
        <div v-else-if="worshipStep === 1">
          <h4>选择祭品（可多选）</h4>
          <a-alert
            message="💰 传统与现代并存，以心意为重"
            type="info"
            show-icon
            style="margin-bottom: 16px"
          />
          <a-checkbox-group
            v-model:value="selectedOfferings"
            style="width: 100%"
          >
            <a-row :gutter="[12, 12]">
              <a-col v-for="offering in offerings" :key="offering.id" :span="6">
                <a-card
                  size="small"
                  class="offering-card"
                  :class="{
                    selected: selectedOfferings.includes(offering.id),
                  }"
                  hoverable
                >
                  <a-checkbox :value="offering.id">
                    <div class="offering-content">
                      <div class="offering-icon">{{ offering.icon }}</div>
                      <div class="offering-info">
                        <div class="offering-name">{{ offering.name }}</div>
                        <div class="offering-meaning">
                          {{ offering.meaning }}
                        </div>
                        <div class="offering-price">{{ offering.price }}</div>
                      </div>
                    </div>
                  </a-checkbox>
                </a-card>
              </a-col>
            </a-row>
          </a-checkbox-group>
        </div>

        <!-- 步骤3: 撰写祭文 -->
        <div v-else-if="worshipStep === 2">
          <h4>撰写祭文</h4>
          <a-form layout="vertical">
            <a-form-item label="祭文标题">
              <a-input
                v-model:value="worshipData.title"
                placeholder="如：清明祭祖"
              />
            </a-form-item>
            <a-form-item label="祭文内容">
              <a-textarea
                v-model:value="worshipData.content"
                :rows="6"
                placeholder="表达对祖先的敬意和思念..."
              />
            </a-form-item>
            <a-form-item>
              <a-checkbox v-model:checked="worshipData.onChain">
                上链存证（生成祭礼SBT）
              </a-checkbox>
            </a-form-item>
          </a-form>
        </div>

        <!-- 步骤4: 完成确认 -->
        <div v-else-if="worshipStep === 3">
          <a-result status="success" title="祭祀准备完成">
            <template #subTitle>
              <p>祭拜：{{ getAncestorName() }}</p>
              <p>祭品：{{ getOfferingsText() }}</p>
              <p>{{ worshipData.onChain ? '将上链生成祭礼SBT' : '不上链' }}</p>
            </template>
          </a-result>
        </div>
      </div>

      <template #footer>
        <a-space>
          <a-button v-if="worshipStep > 0" @click="worshipStep--">
            上一步
          </a-button>
          <a-button
            v-if="worshipStep < 3"
            type="primary"
            @click="worshipStep++"
          >
            下一步
          </a-button>
          <a-button
            v-else
            type="primary"
            @click="submitWorship"
            :loading="submitting"
          >
            完成祭祀
          </a-button>
        </a-space>
      </template>
    </a-modal>

    <!-- 祭祀记录Modal -->
    <a-modal
      v-model:open="recordModalVisible"
      title="📜 我的祭祀记录"
      width="900px"
      :footer="null"
    >
      <a-list :data-source="worshipRecords">
        <template #renderItem="{ item }">
          <a-list-item>
            <a-list-item-meta>
              <template #avatar>
                <a-avatar :src="item.ancestorAvatar" />
              </template>
              <template #title>
                {{ item.title }} - 祭拜{{ item.ancestorName }}
              </template>
              <template #description>
                <div>时间：{{ formatTime(item.time) }}</div>
                <div>祭品：{{ item.offerings.join('、') }}</div>
                <div>祭文：{{ item.content.substring(0, 50) }}...</div>
              </template>
            </a-list-item-meta>
            <div>
              <a-tag v-if="item.sbtMinted" color="gold">
                <SafetyCertificateOutlined /> 已铸造SBT
              </a-tag>
              <a-tag v-else color="blue">未上链</a-tag>
            </div>
          </a-list-item>
        </template>
      </a-list>
    </a-modal>

    <!-- NFT展示墙Modal -->
    <a-modal
      v-model:open="nftModalVisible"
      title="🎨 NFT展示墙"
      width="1000px"
      :footer="null"
    >
      <a-row :gutter="16">
        <a-col v-for="nft in nftList" :key="nft.id" :span="6">
          <a-card hoverable class="nft-card">
            <div class="nft-image" :style="{ background: nft.color }">
              <component :is="nft.icon" style="font-size: 48px; color: white" />
            </div>
            <h4>{{ nft.name }}</h4>
            <p>{{ nft.description }}</p>
            <a-tag color="blue">#{{ nft.tokenId }}</a-tag>
          </a-card>
        </a-col>
      </a-row>
    </a-modal>

    <!-- 牌位信息Modal -->
    <a-modal
      v-model:open="tabletModalVisible"
      :title="`🪧 ${selectedTablet?.name} - 牌位详情`"
      width="800px"
      :footer="null"
    >
      <div v-if="selectedTablet">
        <a-descriptions bordered :column="2" size="small">
          <a-descriptions-item label="姓名">
            <strong>{{ selectedTablet.name }}</strong>
          </a-descriptions-item>
          <a-descriptions-item label="称号">
            {{ selectedTablet.title }}
          </a-descriptions-item>
          <a-descriptions-item label="生卒年份">
            {{ selectedTablet.birthYear }} - {{ selectedTablet.deathYear }}
          </a-descriptions-item>
          <a-descriptions-item label="享年">
            <a-tag color="blue">
              {{ selectedTablet.deathYear - selectedTablet.birthYear }}岁
            </a-tag>
          </a-descriptions-item>
          <a-descriptions-item label="牌位位置">
            {{ selectedTablet.position }}
          </a-descriptions-item>
          <a-descriptions-item label="祭祀次数">
            <a-tag color="red">{{ selectedTablet.worshipCount }}次</a-tag>
          </a-descriptions-item>
          <a-descriptions-item label="主要成就" :span="2">
            {{ selectedTablet.achievement }}
          </a-descriptions-item>
        </a-descriptions>

        <a-divider />

        <h4 style="margin-bottom: 12px">📜 生平简介</h4>
        <a-card size="small" style="background: #f5f5f5">
          <p style="margin: 0; line-height: 1.8">
            {{ selectedTablet.biography }}
          </p>
        </a-card>

        <a-divider />

        <h4 style="margin-bottom: 12px">🕯️ 最近祭祀记录</h4>
        <a-timeline>
          <a-timeline-item
            v-for="record in selectedTablet.recentWorship"
            :key="record.id"
            color="green"
          >
            <p>
              <strong>{{ record.date }}</strong>
            </p>
            <p>祭祀人：{{ record.worshiper }}</p>
            <p>祭品：{{ record.offerings }}</p>
          </a-timeline-item>
        </a-timeline>

        <a-divider />

        <a-space style="width: 100%" direction="vertical" :size="12">
          <a-button
            type="primary"
            block
            size="large"
            @click="worshipThisAncestor(selectedTablet)"
          >
            <FireOutlined /> 祭拜此祖先
          </a-button>
          <a-button block @click="viewFamilyTree(selectedTablet)">
            <TeamOutlined /> 查看族谱关系
          </a-button>
        </a-space>
      </div>
    </a-modal>
  </div>
</template>

<style scoped lang="scss">
.virtual-shrine-3d {
  @keyframes pulse-glow {
    0%,
    100% {
      box-shadow: 0 6px 20px rgb(24 144 255 / 40%);
    }

    50% {
      box-shadow: 0 8px 25px rgb(24 144 255 / 80%);
    }
  }

  position: relative;
  width: 100%;
  height: 800px;
  overflow: hidden;
  background: linear-gradient(to bottom, #87ceeb 0%, #e0f2f1 100%);
  border-radius: 8px;

  .shrine-container {
    width: 100%;
    height: 100%;
  }

  .controls-panel {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 10;
  }

  // 居中开门按钮
  .center-door-button {
    position: absolute;
    bottom: 80px;
    left: 50%;
    z-index: 1000;
    transform: translateX(-50%);

    .door-btn {
      height: 60px;
      padding: 0 30px;
      font-size: 18px;
      font-weight: bold;
      border-radius: 30px;
      box-shadow: 0 6px 20px rgb(24 144 255 / 40%);
      animation: pulse-glow 2s infinite;

      &:hover {
        box-shadow: 0 8px 25px rgb(24 144 255 / 60%);
        transform: translateY(-3px);
      }
    }
  }

  .status-panel {
    position: absolute;
    top: 20px;
    right: 20px;
    z-index: 10;
  }

  .effects-demo-panel {
    position: absolute;
    top: 140px;
    right: 20px;
    z-index: 10;
    width: 200px;

    .effect-category {
      margin-bottom: 12px;

      .category-title {
        padding-left: 4px;
        margin-bottom: 8px;
        font-size: 12px;
        font-weight: bold;
        color: #666;
        border-left: 3px solid #1890ff;
      }

      .ant-btn {
        margin-bottom: 6px;
        font-weight: 600;
        box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
        transition: all 0.3s ease;

        &:hover {
          box-shadow: 0 4px 12px rgb(0 0 0 / 25%);
          transform: translateY(-2px);
        }

        &:active {
          transform: scale(0.95);
        }
      }
    }

    :deep(.ant-card) {
      background: rgb(255 255 255 / 90%);
      box-shadow: 0 4px 16px rgb(0 0 0 / 10%);
      backdrop-filter: blur(10px);

      .ant-card-head {
        min-height: auto;
        padding: 8px 12px;

        .ant-card-head-title {
          padding: 4px 0;
          font-size: 14px;
          font-weight: bold;
        }
      }

      .ant-card-body {
        padding: 12px;
      }
    }
  }

  .help-panel {
    position: absolute;
    bottom: 20px;
    left: 50%;
    z-index: 10;
    max-width: 600px;
    transform: translateX(-50%);

    .help-content {
      display: flex;
      flex-wrap: wrap;
      gap: 20px;
      justify-content: center;

      span {
        white-space: nowrap;
      }
    }
  }

  .nft-card {
    margin-bottom: 16px;
    text-align: center;

    .nft-image {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 120px;
      margin-bottom: 12px;
      border-radius: 4px;
    }

    h4 {
      margin: 8px 0;
      font-size: 14px;
    }

    p {
      margin-bottom: 8px;
      font-size: 12px;
      color: #666;
    }
  }
}

:deep(.ant-card.selected) {
  border-color: #1890ff;
  box-shadow: 0 0 8px rgb(24 144 255 / 30%);
}

// 祭品卡片样式
.offering-card {
  height: 100%;
  cursor: pointer;
  transition: all 0.3s ease;

  &.selected {
    background: #f6ffed;
    border-color: #52c41a !important;
    box-shadow: 0 0 12px rgb(82 196 26 / 40%) !important;
  }

  &:hover {
    transform: translateY(-2px);
  }

  :deep(.ant-card-body) {
    padding: 8px !important;
  }

  .offering-content {
    display: flex;
    gap: 8px;
    align-items: center;

    .offering-icon {
      flex-shrink: 0;
      font-size: 32px;
      line-height: 1;
    }

    .offering-info {
      flex: 1;
      min-width: 0;

      .offering-name {
        display: -webkit-box;
        margin-bottom: 2px;
        overflow: hidden;
        text-overflow: ellipsis;
        -webkit-line-clamp: 2;
        font-size: 13px;
        font-weight: 600;
        line-height: 1.3;
        color: #333;
        -webkit-box-orient: vertical;
      }

      .offering-meaning {
        margin-bottom: 2px;
        overflow: hidden;
        text-overflow: ellipsis;
        font-size: 11px;
        color: #666;
        white-space: nowrap;
      }

      .offering-price {
        font-family: Arial, sans-serif;
        font-size: 13px;
        font-weight: bold;
        color: #f5222d;
      }
    }
  }
}
</style>
